# -*- coding: utf-8 -*-
"""
 * @file bufferpool.py
 * @author SDK_TEAM
 * @brief
 * @version 0.1
 * @date 2022-11-3
 * Copyright:
 * © 2018 北京灵汐科技有限公司 版权所有。
 * 注意：以下内容均为北京灵汐科技有限公司原创，未经本公司允许，不得转载，否则将视为侵权；对于不遵守此声明或者其他违法使用以下内容者，本公司依法保留追究权。
 * © 2018 Lynxi Technologies Co., Ltd. All rights reserved.
 * NOTICE: All information contained here is, and remains the property of Lynxi. This file can not
 * be copied or distributed without the permission of Lynxi Technologies Co., Ltd.
"""

from collections import deque
import threading
import pylynchipsdk as sdk

class buffer_pool:
    def __init__(self, elemsize, maxszie):
        self.isinit = False
        self.elemsize = elemsize
        self.maxszie = maxszie
        self.mutex = threading.Lock()
        self.not_empty = threading.Condition(self.mutex)
        self.is_full = threading.Condition(self.mutex)
        self.queue = deque()
        for x in range(maxszie):
            addr, ret = sdk.lyn_malloc(elemsize)
            self.queue.append(addr)
        self.isinit = True

    def free_buffers(self):
        if not self.isinit:
            raise ValueError("buffer pool not init")

        with self.mutex :
            while self._qsize() < self.maxszie:
                self.is_full.wait()
            for addr in self.queue:
                sdk.lyn_free(addr)
            self.isinit = False

    def full(self):
        if not self.isinit:
            raise ValueError("buffer pool not init")
        with self.mutex :
            return 0 < self.maxszie <= self._qsize()

    def empty(self):
        if not self.isinit:
            raise ValueError("buffer pool not init")
        with self.mutex :
            return not self._qsize()

    def push(self, item):
        if not self.isinit:
            raise ValueError("buffer pool not init")
        if self.full():
            raise ValueError("buffer pool is full")

        with self.mutex :
            self.queue.append(item)
            self.not_empty.notify()
            if self._qsize() >= self.maxszie:
                self.is_full.notify()

    def pop(self):
        if not self.isinit:
            raise ValueError("buffer pool not init")

        with self.mutex :
            while self._qsize() == 0 :
                self.not_empty.wait()
            item = self.queue.popleft()
            return item

    def qsize(self):
        with self.mutex:
            return self._qsize()

    def _qsize(self):
        return len(self.queue)